package dynamicGui;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;

import javax.swing.*;

import netcode.client.Client;
import netcode.helper.ClientMessageListener;
import netcode.helper.NetcodeHelper;

import gamePlay.*;
import gui.MenuCycling;

/*
 * This method runs through the whole game by having one JFrame which is changed by all the methods
 * -calls display methods which create JPanels and adds them to the main JFrame
 * -handles all the game operations and network calls
 * 
 */

public class MenuCyclingE implements ClientMessageListener {
	static JFrame frame = new JFrame(); // frame for GUI displays
	static StartingMenuE startingMenuE_;
	static LobbySelectionMenuE lobbySelectionMenuE_;
	static LobbyMenuHostE lobbyMenuHost_;
	static LobbyMenuGuestE lobbyMenuGuest_;

	static private QuestionMenu questionMenu_;
	static private BetMenuE betMenu_;
	static private ResultsMenuE resultsMenu_;

	static Game game_;

	// networking variables
	static Client client_;
	static boolean serverLobbyInfoReceived = false;
	static boolean gameLobbyInfoReceived = false;
	static boolean questionReceived = false;
	static boolean bettingOddsReceived = false;
	static boolean roundResultsReceived = false;
	static boolean endOfGameReceived = false;

	// static Player p1;
	// static Player p2;
	// static Player p3;
	// static Player p4;
	// static Player p5;
	// static Player p6;
	// static ArrayList<Integer> displayAnswers;
	// static ArrayList<Integer> sortedAnswers = new ArrayList<Integer>();
	// static ArrayList <Integer> odds = new ArrayList<Integer>();
	// static ArrayList <Integer> payouts = new ArrayList<Integer>();
	// static int num_Players;
	static int round = 0;

	// static LobbySelectionMenu lobbySelectionScreen;
	// static LobbyMenu hostLobbyScreen;
	static int screenSize = 2;

	public static void main(String args[]) {
		MenuCyclingE test = new MenuCyclingE();
		test.begin();
	}

	public void begin() {
		// Instatiate variables
		game_ = new Game();

		String usersName;
		boolean isValidUsersName = false;
		do {
			usersName = (String) JOptionPane.showInputDialog(frame,
					"What's your name?", JOptionPane.PLAIN_MESSAGE);
			try {
				int number = Integer.parseInt(usersName);
			} catch (Exception e) {
				isValidUsersName = true;
			}
		} while (!isValidUsersName);

		// Enzo-implement network stuff
		try {

			client_ = new Client(NetcodeHelper.SERVER_ADDRESS,
					NetcodeHelper.SERVER_PORT, usersName, game_);
			client_.setListener(this);
			// This is an important part.
			client_.start();
			client_.sendConnectionRequest();
			questionMenu_ = new QuestionMenu();

		} catch (Exception e) {
			System.err.println(e);
		}

		startingMenuE_ = new StartingMenuE(screenSize);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(startingMenuE_);
		frame.pack();
		frame.repaint();
		frame.setVisible(true);

	}

	// initializes the game state
	public static void startGame(int num_play) {

		int num_Players = num_play;
		// integration testing
		game_ = new Game("Good Team", num_Players);
		String name = JOptionPane.showInputDialog("Enter your name.");
		Player p1 = new Player(name);
		p1.joinGame(game_);
		for (int i = 1; i < num_Players; i++) {
			ComputerPlayer comp = new ComputerPlayer("Computer " + i + "");
			comp.joinGame(game_);
		}

		// if (num_Players >= 3){
		// p2 = new ComputerPlayer("CPU 1");
		// p2.joinGame(g);
		// p3 = new ComputerPlayer("CPU 2");
		// p3.joinGame(g);
		// if (num_Players >= 4){
		// p4 = new ComputerPlayer("CPU 3");
		// p4.joinGame(g);
		// if(num_Players >= 5){
		// p5 = new ComputerPlayer("CPU 4");
		// p5.joinGame(g);
		// if (num_Players == 6){
		// p6 = new ComputerPlayer("CPU 5");
		// p6.joinGame(g);
		// }
		// }
		// }
		// }
		// betScreen = new BetMenu(screenSize);
		// betTimer = new javax.swing.Timer(1000, betScreen.new
		// TimerListener());
		// resultScreen = new ResultsMenu();
		// resultTimer = new javax.swing.Timer(1000, resultScreen.new
		// TimerListener());
		// winScreen = new WinMenu(screenSize);
		// winTimer = new javax.swing.Timer(1000, winScreen.new
		// TimerListener());
		game_.createMenus(screenSize);
		displayQuestionMenu();
	}

	// returns the current question
	public static String getQuestion() {
		return game_.getQuestionGUI();
	}

	// returns the correct answer
	public static int getAnswer() {
		return game_.getAnswer();
	}

	// returns the Chip count of the Player
	// public static int getPlayerChips(){
	// return p1.getGame_chips() + p1.getPermanent_chips();
	// }

	// submit the guesses of all players. Currently uses a static guess for each
	// player except the user
	public static void guess(Integer playerGuess) {
		game_.getPlayers().get(0).submitGuess(playerGuess);
		for (int i = 1; i < game_.getPlayers().size(); i++) {
			ComputerPlayer comp = ((ComputerPlayer) (game_.getPlayers().get(i)));
			comp.submitGuess(game_.getQuestion().getAnswer());
		}
		// if (num_Players >= 3){
		// p2.submitGuess(g.getQuestion().getAnswer());
		// p3.submitGuess(g.getQuestion().getAnswer());
		// if (num_Players >= 4){
		// p4.submitGuess(g.getQuestion().getAnswer());
		// if(num_Players >= 5){
		// p5.submitGuess(g.getQuestion().getAnswer());
		// if (num_Players == 6){
		// p6.submitGuess(g.getQuestion().getAnswer());
		// }
		// }
		// }
		// }
		// TODO make sure this isn't fucked
		// displayAnswers = g.answers();
	}

	// return the best answer of all answers submitted.
	public static int getBest() {

		int answer = game_.getAnswer();
		ArrayList<Guess> guesses = (ArrayList<Guess>) game_.getGuesses();
		Guess winner = guesses.get(0);
		int win_location = 0;
		// The for loop below determines which guess was closest to the answer
		for (int i = 0; i < guesses.size(); i++) {
			int difference = Math.abs(answer - guesses.get(i).getGuess());
			if (difference < (Math.abs(answer - winner.getGuess()))) {
				winner = guesses.get(i);
				win_location = i;
			}
		}
		return winner.getGuess();
		// TODO messed with this still, confirm working
		// int correct = getAnswer();
		//
		// for(int i = sortedAnswers.size() - 1;i >=0;i--)
		// if(sortedAnswers.get(i) <= correct)
		// return sortedAnswers.get(i);
		// return 0;
		//
	}

	public static void updateQuestions() {
		game_.updateQuestions();
	}
	
	
	
	
	
	
	
	
	
	
	
	

	// BEGIN All menu cycling/displaying activities
	// below---------------------------------------------------------------
	public static void displayStartingMenu() {
		frame.getContentPane().removeAll();
		round = 0;
		// update the frame
		frame.add(startingMenuE_);
		frame.validate();
		frame.pack();
		frame.repaint();
		frame.setVisible(true);
	}

	public static void displayLobbySelectionMenu() {
		// gather client information and update before creating the gui
		serverLobbyInfoReceived = false;
		do {
			client_.sendServerLobbyInfoRequest();
			sleepyTime();
		} while (!serverLobbyInfoReceived);
		// Only create the GUI after the game object has been updated
		// lobbySelectionMenuE = new LobbySelectionMenuE(client_.getLobby());
		lobbySelectionMenuE_ = new LobbySelectionMenuE();

		frame.getContentPane().removeAll();
		// update the frame
		frame.add(lobbySelectionMenuE_);
		frame.validate();
		frame.pack();
		frame.repaint();
		frame.setVisible(true);
	}

	public static void displayLobbyMenuHost() {
		// gather client information and update before creating the gui
		boolean isValidUsersName = false;
		String gameName;
		do {
			gameName = (String) JOptionPane.showInputDialog(frame,
					"GameServerName: ", JOptionPane.PLAIN_MESSAGE);
			try {
				int number = Integer.parseInt(gameName);
			} catch (Exception e) {
				isValidUsersName = true;
			}
		} while (!isValidUsersName);

		boolean isValidNumberOfRounds = true;
		int numberOfRounds = 1;// default to 1 round
		do {
			String numberOfRoundsString = JOptionPane.showInputDialog(frame,
					"How many rounds? ", JOptionPane.PLAIN_MESSAGE);
			try {
				int number = Integer.parseInt(numberOfRoundsString);// make sure this is an int
				numberOfRounds = Math.abs(number);// take the absolute value of what they entered, no negative rounds
				isValidNumberOfRounds = true;
			} catch (NumberFormatException e) {
				isValidNumberOfRounds = false;
			}
		} while (!isValidNumberOfRounds);

		client_.sendCreateGameRequest(gameName, numberOfRounds, new String[] {});// Enzo-this needs sleepytime for the gui to update, Currently there is an auto refresh in the lobbyhost which is a mild fix
																
		
		lobbyMenuHost_ = new LobbyMenuHostE();
		frame.remove(lobbySelectionMenuE_);
		// update the frame
		frame.add(lobbyMenuHost_);
		frame.validate();
		frame.pack();
		frame.repaint();
		frame.setVisible(true);
	}

	public static void displayLobbyMenuGuest(int gameIDin) {
		// gather client information and update before creating the gui
		gameLobbyInfoReceived = false;
		do {
			client_.sendJoinGameRequest(gameIDin);
			sleepyTime();
		} while (!gameLobbyInfoReceived);
		// Only create the GUI after the game object has been updated
		lobbyMenuGuest_ = new LobbyMenuGuestE();

		frame.remove(lobbySelectionMenuE_);
		// update the frame
		frame.add(lobbyMenuGuest_);
		frame.validate();
		frame.pack();
		frame.repaint();
		frame.setVisible(true);
	}

	// This method will change the frame to display the Question panel
	public static void displayQuestionMenu() {
		// gather client information and update before creating the gui
		questionReceived = false;
		do {
			sleepyTime();
		} while (!questionReceived);

		// game_.resultTimer.stop();
		// game_.resultsMenu.seconds = 60;
		frame.getContentPane().removeAll();
		round++;
		// update the frame
		// questionMenu_ = new QuestionMenu(screenSize, client_, game_);

		// game_.updateQuestions();
		questionMenu_.setQuestion();
		questionMenu_.clearFields();
		// game_.questTimer.start();
		frame.add(questionMenu_);
		frame.validate();
		frame.pack();
		frame.repaint();
		frame.setVisible(true);
	}

	public static void displayBetMenu() {
		// Wait for other players before displaying the betmenu
		System.out.println("Waiting for other players... to finish answering before displaying bet");
		do {
			sleepyTime();
		} while (!bettingOddsReceived);
		bettingOddsReceived = false;

		betMenu_ = new BetMenuE();

		// game_.questTimer.stop();
		// game_.questionMenu.seconds = 30;
		// betMenu_.refreshAnswers();
		// betMenu_.setChips();

		frame.remove(questionMenu_);
		// game_.betTimer.start();
		// update the frame
		frame.add(betMenu_);
		frame.validate();
		frame.pack();
		frame.repaint();
		frame.setVisible(true);
	}

	public static void displayResultsMenu() {
		// MenuCycling.p1.setPermanent_chips(2);

		// frame.remove(game_.betScreen);
		// game_.betTimer.stop();
		// game_.betScreen.seconds = 30;
		//
		// // update the frame
		// if (round == 7){
		// game_.winScreen.setText();
		// game_.winTimer.start();
		// game_.winScreen.refreshAnswers();
		// frame.add(game_.winScreen);
		// }
		// else{
		// game_.resultScreen.setText();
		// game_.resultTimer.start();
		// game_.resultScreen.refreshAnswers();
		// frame.add(game_.resultScreen);
		// }
		// frame.validate();
		// frame.pack();
		// frame.repaint();
		// frame.setVisible(true);

		
		
		// E
		game_.clearBets();
		//Wait for other players before displaying the results
		System.out.println("Waiting for other players... to finish betting before displaying results");
		do {
			sleepyTime();
		} while (!MenuCyclingE.roundResultsReceived);
		roundResultsReceived = false;
		
		
		resultsMenu_ = new ResultsMenuE();
		frame.remove(betMenu_);
		frame.add(resultsMenu_);
		frame.validate();
		frame.pack();
		frame.repaint();
		frame.setVisible(true);
	}

	// END All menu cycling/displaying
	// activities---------------------------------------------------------------

	// Implemented from Team Alpha's Multiplayer Test
	/**
	 * Waits for some time so that a message has time to be received.
	 */
	public static void sleepyTime() {
		try {
			Thread.sleep(NetcodeHelper.MILLISECONDS_BETWEEN_SENDING_MESSAGE);
		} catch (Exception e) {
			System.err.println(e);
		}
	}

	// copied over from Team Alpha's multiplayer test
	@Override
	public void onMessageReceived(byte packetCode) {
		System.out.println("onMessageReceived() entered with code: "
				+ packetCode);
		switch (packetCode) {
		case NetcodeHelper.SERVER_LOBBY_INFO_RESPONSE:
			serverLobbyInfoReceived = true;
			break;
		case NetcodeHelper.GAME_LOBBY_INFO:
			gameLobbyInfoReceived = true;
			break;
		case NetcodeHelper.QUESTION:
			questionReceived = true;
			break;
		case NetcodeHelper.BETTING_ODDS:
			bettingOddsReceived = true;
			break;
		case NetcodeHelper.ROUND_RESULTS:
			roundResultsReceived = true;
			break;
		case NetcodeHelper.GAME_RESULTS:
			endOfGameReceived = true;
			break;
		}

	}

}